package com.boarsoft.boar.batch.runner;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.boarsoft.flow.core.SimpleFlow;
import com.boarsoft.flow.service.SimpleFlowService;
import com.boarsoft.flow.store.SimpleFlowPersister;

/**
 * 批量冲正，批量（远程）调起冲正交易<br>
 * 批量调度中不会定义，更不会不运行任何具体的冲正交易
 * 
 * @author Mac_J
 *
 */
@Deprecated
public class BatchReverseRunner implements Runnable, BatchReverseConfig, ApplicationContextAware {
	private static final Logger log = LoggerFactory.getLogger(BatchReverseRunner.class);

	/** */
	protected SimpleFlowPersister persister;
	/** */
	protected ExecutorService threadPool;
	/** */
	protected int max1 = 500;
	/** */
	protected int max2 = 500;
	/** */
	protected int max3 = 500;

	protected AtomicBoolean running = new AtomicBoolean(true);

	protected ApplicationContext applicationContext;

	@PostConstruct
	public void init() {
		threadPool.execute(this);
	}

	@PreDestroy
	public void destroy() {
		running.set(false);
	}

	@Override
	public void run() {
		while (running.get()) {
			// 所有max都小于等于1就不执行
			if (max1 < 1 && max2 < 1 && max3 < 1) {
				log.warn("Batch reverse limit is invalid: {}/{}/{}", max1, max2, max3);
				try {
					Thread.sleep(3000L);
				} catch (InterruptedException e) {
					if (!running.get()) {
						return;
					}
					log.error("Be interrupted while sleep for valid batch reverse limit");
				}
			}
			// 检查一批待执行的冲正，并修改它们的状态为正在冲正（避免兄弟实例把它查出来）
			List<SimpleFlow> foLt = persister.list(max1, max2, max3);
			if (foLt == null || foLt.isEmpty()) {
				// log.debug("No batch reverse request");
				try {
					Thread.sleep(3000L);
				} catch (InterruptedException e) {
					if (!running.get()) {
						return;
					}
					log.warn("Be interrupted while sleep for batch reverse task");
				}
				continue;
			}
			// 逐条异步（并行）调起远程的冲正流程
			int total = foLt.size();
			log.info("Locked {} batch reverses to do", total);
			long maxTimeout = 0L;
			final CountDownLatch cdl = new CountDownLatch(total);
			for (final SimpleFlow fo : foLt) {
				try {
					final SimpleFlowService sfs = //
							(SimpleFlowService) applicationContext.getBean(fo.getRevCode());
					final SimpleFlow rf = (SimpleFlow)sfs.create();
					rf.setRevFor(fo.getId());
					rf.setData(fo.getData());
					rf.setEntry(fo.getRevEntry());
					// 不能用本地流程引擎来跑这个flow，因为这个flow的节点在本地不存在
					// 同时由于本线程需要等待这些流程执行完成，因此没有必要等待回调
					threadPool.execute(new Runnable() {
						@Override
						public void run() {
							try {
								sfs.start(rf);
							} catch (Throwable e) {
								log.error("Error on invoke reverser {} of flow {}", rf, fo, e);
								fo.setRevStatus(SimpleFlow.REV_FAILED);
								fo.setRevError(e);
								persister.update(fo);
							} finally {
								cdl.countDown();
							}
						}
					});
					maxTimeout = Math.max(maxTimeout, rf.getTimeout());
				} catch (Throwable e) {
					cdl.countDown();
					log.error("Error on create or invoke reverser of flow {}", fo, e);
					fo.setRevStatus(SimpleFlow.REV_FAILED);
					fo.setRevError(e);
					persister.update(fo);
				}
			}
			// 等待这些冲正全部完成（成功、失败或超时）再继续下一轮处理
			try {
				cdl.await(maxTimeout, TimeUnit.MILLISECONDS);
			} catch (InterruptedException e) {
				log.error("Be interrupted on await batch reverses", e);
			}
		}
	}

	public ExecutorService getThreadPool() {
		return threadPool;
	}

	public void setThreadPool(ExecutorService threadPool) {
		this.threadPool = threadPool;
	}

	@Override
	public int getMax1() {
		return max1;
	}

	@Override
	public void setMax1(int max1) {
		this.max1 = max1;
	}

	@Override
	public int getMax2() {
		return max2;
	}

	@Override
	public void setMax2(int max2) {
		this.max2 = max2;
	}

	@Override
	public int getMax3() {
		return max3;
	}

	@Override
	public void setMax3(int max3) {
		this.max3 = max3;
	}

	public SimpleFlowPersister getPersister() {
		return persister;
	}

	public void setPersister(SimpleFlowPersister persister) {
		this.persister = persister;
	}

	public ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	public void setApplicationContext(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}
}
